﻿using System;
using System.Linq.Expressions;

namespace IInject.Registration
{
	///<summary>
	/// Provides an interface for building <see cref="RegistryContext"/>s.
	///</summary>
	public interface IContextBuilder : IDisposable
	{
		///<summary>
		/// Registers the current configuration with the <see cref="Container"/>.
		///</summary>
		///<returns>The current <see cref="IContainer"/>.</returns>
		IContainer Apply();
		///<summary>
		/// Adds the type used to register the <see cref="RegistryContext"/>.
		///</summary>
		///<typeparam name="T">The type used to register the <see cref="RegistryContext"/>.</typeparam>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder<T> From<T>();
		///<summary>
		/// Adds the type used to register the <see cref="RegistryContext"/>.
		///</summary>
		///<param name="fromType">The type used to register the <see cref="RegistryContext"/>.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder From(Type fromType);
		///<summary>
		/// Adds the type the <see cref="IContainer"/> will return when resolved.
		///</summary>
		///<param name="toType">The type the <see cref="IContainer"/> will return when resolved.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder To(Type toType);
		///<summary>
		/// Adds the delegate to the <see cref="RegistryContext"/> to be called when resolving this type.
		///</summary>
		///<typeparam name="T"></typeparam>
		///<param name="resolver">The lambda to call.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder To<T>(Func<IContainer, object> resolver);
		///<summary>
		/// Adds a key to use when registering the <see cref="RegistryContext"/>.
		///</summary>
		///<param name="key">The key to use when registering the <see cref="RegistryContext"/>.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder With(string key);
		///<summary>
		/// Adds the <see cref="Scope"/> associated with the instance of the resolved type.
		///</summary>
		///<param name="scope">The <see cref="Scope"/> associated with the instance of the resolved type.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder With(Scope scope);
		///<summary>
		/// The instance to return when resolved.
		///</summary>
		///<param name="instance">The instance to return when resolved.</param>
		///<typeparam name="T">The type of object to return.</typeparam>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder Return<T>(T instance);
		/// <summary>
		/// Registers the selected property to be injected.
		/// </summary>
		/// <typeparam name="T">The parent type used to get the property.</typeparam>
		/// <param name="propExpression">The Func{T, object} used to select the property.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder Inject<T>(Expression<Func<T, object>> propExpression);
	}

	///<summary>
	/// Provides a generic interface for building <see cref="RegistryContext"/>s.
	///</summary>
	///<typeparam name="TFrom"></typeparam>
	public interface IContextBuilder<TFrom> : IContextBuilder
	{
		///<summary>
		/// Adds the type the <see cref="IContainer"/> will return when resolved.
		///</summary>
		///<typeparam name="TTo">The type the <see cref="IContainer"/> will return when resolved.</typeparam>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder<TFrom> To<TTo>() where TTo : TFrom;

		/// <summary>
		/// Registers the selected property to be injected.
		/// </summary>
		/// <param name="propExpression">The Func{T, object} used to select the property.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder<TFrom> Inject(Expression<Func<TFrom, object>> propExpression);

		/// <summary>
		/// Registers the selected property to be injected.
		/// </summary>
		/// <param name="propExpression">The Func{T, object} used to select the property.</param>
		///<returns>The current <see cref="IContextBuilder"/>.</returns>
		IContextBuilder<TFrom> Inject<T>(Expression<Func<TFrom, T>> propExpression, T value);
	}

	/*///<summary>
	/// Provides a generic interface for building <see cref="RegistryContext"/>s.
	///</summary>
	///<typeparam name="TFrom"></typeparam>
	///<typeparam name="TTo"></typeparam>*/
	//public interface IContextBuilder<TFrom, TTo> : IContextBuilder<TFrom> where TTo : TFrom
	//{
	//    /// <summary>
	//    /// Registers the selected property to be injected.
	//    /// </summary>
	//    /// <param name="propExpression">The Func{TTo, object} used to select the property.</param>
	//    ///<returns>The current <see cref="IContextBuilder"/>.</returns>
	//    IContextBuilder<TFrom, TTo> Inject(Expression<Func<TTo, object>> propExpression);
	//}
}
